using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace WPFTemplateLib.Controls.Panels
{
	/// <summary>
	/// [GitHub Copilot] 在 AdornerLayer 顶层绘制分隔线的 StackPanel，不修改 Children，适合作为 ItemsPanel。
	/// <para/>已知问题：线条处于最上层。
	/// </summary>
	public class AdornerSeparatorStackPanel : StackPanel
	{
		#region 构造

		public AdornerSeparatorStackPanel()
		{
			SnapsToDevicePixels = true;
			Loaded += OnLoaded;
			Unloaded += OnUnloaded;
		}

		#endregion

		#region 依赖属性

		public static readonly DependencyProperty IsShowSeparatorProperty = DependencyProperty.Register(
			nameof(IsShowSeparator), typeof(bool), typeof(AdornerSeparatorStackPanel),
			new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender, OnSeparatorPropChanged));
		/// <summary>
		/// 是否显示分隔线
		/// </summary>
		public bool IsShowSeparator
		{
			get => (bool)GetValue(IsShowSeparatorProperty);
			set => SetValue(IsShowSeparatorProperty, value);
		}

		public static readonly DependencyProperty SeparatorBrushProperty = DependencyProperty.Register(
			nameof(SeparatorBrush), typeof(Brush), typeof(AdornerSeparatorStackPanel),
			new FrameworkPropertyMetadata(Brushes.LightGray, FrameworkPropertyMetadataOptions.AffectsRender, OnSeparatorPropChanged));
		/// <summary>
		/// 分隔线画刷
		/// </summary>
		public Brush SeparatorBrush
		{
			get => (Brush)GetValue(SeparatorBrushProperty);
			set => SetValue(SeparatorBrushProperty, value);
		}

		public static readonly DependencyProperty SeparatorThicknessProperty = DependencyProperty.Register(
			nameof(SeparatorThickness), typeof(double), typeof(AdornerSeparatorStackPanel),
			new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSeparatorPropChanged));
		/// <summary>
		/// 分隔线粗细（DIP，设备无关像素）。
		/// </summary>
		public double SeparatorThickness
		{
			get => (double)GetValue(SeparatorThicknessProperty);
			set => SetValue(SeparatorThicknessProperty, value);
		}

		public static readonly DependencyProperty SeparatorInsetProperty = DependencyProperty.Register(
			nameof(SeparatorInset), typeof(double), typeof(AdornerSeparatorStackPanel),
			new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender, OnSeparatorPropChanged));
		/// <summary>
		/// 分隔线两端缩进（水平为上下内缩，垂直为左右内缩）
		/// </summary>
		public double SeparatorInset
		{
			get => (double)GetValue(SeparatorInsetProperty);
			set => SetValue(SeparatorInsetProperty, value);
		}

		private static void OnSeparatorPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			if (d is AdornerSeparatorStackPanel p)
			{
				p._adorner?.InvalidateVisual();
			}
		}

		#endregion

		#region Adorner 顶层绘制

		private SeparatorAdorner _adorner;

		private void OnLoaded(object sender, RoutedEventArgs e)
		{
			EnsureAdorner();
		}

		private void OnUnloaded(object sender, RoutedEventArgs e)
		{
			RemoveAdorner();
		}

		private void EnsureAdorner()
		{
			var layer = AdornerLayer.GetAdornerLayer(this);
			if (layer == null) return;
			if (_adorner == null)
			{
				_adorner = new SeparatorAdorner(this);
				layer.Add(_adorner);
			}
			else
			{
				_adorner.InvalidateVisual();
			}
		}

		private void RemoveAdorner()
		{
			var layer = AdornerLayer.GetAdornerLayer(this);
			if (layer == null) return;
			if (_adorner != null)
			{
				layer.Remove(_adorner);
				_adorner = null;
			}
		}

		#endregion

		#region 变更触发重绘

		protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
		{
			base.OnVisualChildrenChanged(visualAdded, visualRemoved);
			_adorner?.InvalidateVisual();
		}

		protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
		{
			base.OnRenderSizeChanged(sizeInfo);
			_adorner?.InvalidateVisual();
		}

		#endregion

		#region 内部 Adorner

		private sealed class SeparatorAdorner : Adorner
		{
			private readonly AdornerSeparatorStackPanel _owner;

			public SeparatorAdorner(AdornerSeparatorStackPanel owner) : base(owner)
			{
				_owner = owner;
				IsHitTestVisible = false;
				SnapsToDevicePixels = true;
				RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);
			}

			protected override void OnRender(DrawingContext dc)
			{
				base.OnRender(dc);

				if (!_owner.IsShowSeparator || _owner.SeparatorBrush == null) return;
				int count = _owner.InternalChildren?.Count ?? 0;
				if (count < 2) return;
				if (_owner.SeparatorThickness <= 0) return;

				var dpi = VisualTreeHelper.GetDpi(_owner);

				if (_owner.Orientation == Orientation.Horizontal)
				{
					// 垂直分隔线：使用 DIP 粗细，仅对坐标做像素/半像素对齐
					var pen = new Pen(_owner.SeparatorBrush, _owner.SeparatorThickness);
					if (pen.CanFreeze) pen.Freeze();

					double pixelThickness = _owner.SeparatorThickness * dpi.DpiScaleX;
					bool isOddPx = ((int)Math.Round(pixelThickness)) % 2 == 1;

					for (int i = 0; i < count - 1; i++)
					{
						var child = _owner.InternalChildren[i] as UIElement;
						if (child == null || child.Visibility != Visibility.Visible) continue;

						// 子元素右边界 X（DIP） + 其 Margin.Right
						double x = child.TranslatePoint(new Point(child.RenderSize.Width, 0), _owner).X;
						double marginRight = 0;
						if (child is FrameworkElement feH) marginRight = feH.Margin.Right;
						x += marginRight; // 加上边距，使分隔线绘制在“元素边缘+边距”位置

						// 像素对齐 + 奇数像素半偏移
						double xPixels = Math.Round(x * dpi.DpiScaleX) + (isOddPx ? 0.5 : 0.0);
						double xAligned = xPixels / dpi.DpiScaleX;

						double y1 = _owner.SeparatorInset;
						double y2 = Math.Max(0, _owner.ActualHeight - _owner.SeparatorInset);

						var guidelines = new GuidelineSet();
						guidelines.GuidelinesX.Add(xAligned);
						dc.PushGuidelineSet(guidelines);
						dc.DrawLine(pen, new Point(xAligned, y1), new Point(xAligned, y2));
						dc.Pop();
					}
				}
				else // Vertical
				{
					// 水平分隔线：使用 DIP 粗细，仅对坐标做像素/半像素对齐
					var pen = new Pen(_owner.SeparatorBrush, _owner.SeparatorThickness);
					if (pen.CanFreeze) pen.Freeze();

					double pixelThickness = _owner.SeparatorThickness * dpi.DpiScaleY;
					bool isOddPx = ((int)Math.Round(pixelThickness)) % 2 == 1;

					for (int i = 0; i < count - 1; i++)
					{
						var child = _owner.InternalChildren[i] as UIElement;
						if (child == null || child.Visibility != Visibility.Visible) continue;

						// 子元素下边界 Y（DIP） + 其 Margin.Bottom
						double y = child.TranslatePoint(new Point(0, child.RenderSize.Height), _owner).Y;
						double marginBottom = 0;
						if (child is FrameworkElement feV) marginBottom = feV.Margin.Bottom;
						y += marginBottom; // 加上边距，使分隔线绘制在“元素边缘+边距”位置

						// 像素对齐 + 奇数像素半偏移
						double yPixels = Math.Round(y * dpi.DpiScaleY) + (isOddPx ? 0.5 : 0.0);
						double yAligned = yPixels / dpi.DpiScaleY;

						double x1 = _owner.SeparatorInset;
						double x2 = Math.Max(0, _owner.ActualWidth - _owner.SeparatorInset);

						var guidelines = new GuidelineSet();
						guidelines.GuidelinesY.Add(yAligned);
						dc.PushGuidelineSet(guidelines);
						dc.DrawLine(pen, new Point(x1, yAligned), new Point(x2, yAligned));
						dc.Pop();
					}
				}
			}
		}

		#endregion
	}
}
